package builder

import (
	"errors"
	"fmt"
	"reflect"
	"strings"
	"yunj/pkg/yunj/core/builder/form"
	errcodeEnum "yunj/pkg/yunj/core/enum/errcode"
	"yunj/pkg/yunj/core/response"
	yunjValidator "yunj/pkg/yunj/core/validator"
	"yunj/pkg/yunj/util"

	"github.com/gin-gonic/gin"
	"github.com/worklz/go-validate"
	"golang.org/x/exp/slices"
)

type BuilderInterface interface {
	// 其他包不会用到的方法定义为私有
	GetType() (typ string, err error)                    // 获取构建器类型
	GetId() (id string, err error)                       // 获取构建器id
	SetId(id string) error                               // 设置构建器id
	GetGinContext() *gin.Context                         // 获取gin上下文
	handleActionFuns(actions ...string)                  // 执行操作处理方法集合
	GetError() error                                     // 获取构建器错误
	Assign()                                             // 渲染输出
	View()                                               // 视图渲染输出
	viewArgs() (args map[string]any)                     // 构建器视图模板配置数据
	BeforeHandleAsync(params map[string]any) (err error) // 异步处理前执行
	Async()                                              // 异步输出
}

type Builder struct {
	Type              string                      // 类型
	Id                string                      // 唯一标识
	GinContext        *gin.Context                // gin上下文
	ScriptFileList    []string                    // js脚本文件列表
	BuilderValidator  validate.ValidatorInterface // 构建器验证器
	ValidatorInstance validate.ValidatorInterface // 验证器实例
	ActionHandleSort  []string                    // 操作执行排序
	ActionHandleFuns  map[string][]any            // 操作的处理方法集合
	ErrPrefix         string                      // 错误前缀
	Err               error                       // 错误

	// 父结构体属性
	builderInstance     BuilderInterface // 构建器实例
	builderInstancePtr  reflect.Value    // 构建器实例的指针（调用方法）
	builderInstanceElem reflect.Value    // 构建器实例指针指向的反射值（设置/获取属性值）
}

// 设置构建器实例
func SetBuilderInstance(b *Builder, builderInstance BuilderInterface) {
	b.builderInstance = builderInstance

	// 获取指针的反射值
	builderInstanceValue := reflect.ValueOf(b.builderInstance)
	// 检查传入的是否为指针
	if builderInstanceValue.Kind() != reflect.Ptr || builderInstanceValue.IsNil() {
		b.setError("请传入构建器实例指针值！")
	} else {
		// 获取实际对象的指针
		b.builderInstancePtr = builderInstanceValue
		// 获取实际对象指针指向的反射值
		b.builderInstanceElem = builderInstanceValue.Elem()
	}
}

// 获取字段类型
func (b *Builder) GetType() (typ string, err error) {
	err = b.GetError()
	if err != nil {
		return
	}
	typ = b.Type
	return
}

// 获取构建器id
func (b *Builder) GetId() (id string, err error) {
	err = b.GetError()
	if err != nil {
		return
	}
	id = b.Id
	return
}

// 设置构建器id
func (b *Builder) SetId(id string) (err error) {
	err = b.GetError()
	if err != nil {
		return
	}
	b.Id = id
	return
}

// 获取构建器gin上下文
func (b *Builder) GetGinContext() *gin.Context {
	return b.GinContext
}

// 获取构建器js脚本文件列表
func (b *Builder) GetScriptFileList() (list []string, err error) {
	err = b.GetError()
	if err != nil {
		return
	}
	list = b.ScriptFileList
	return
}

// 设置构建器js脚本文件列表
func (b *Builder) SetScriptFileList(list []string) (err error) {
	err = b.GetError()
	if err != nil {
		return
	}
	b.ScriptFileList = list
	return
}

// 获取构建器验证器
func (b *Builder) GetBuilderValidator() (res validate.ValidatorInterface, err error) {
	err = b.GetError()
	if err != nil {
		return
	}
	res = b.BuilderValidator
	return
}

// 获取链式操作配置的验证器实例
func (b *Builder) GetValidatorInstance() (res validate.ValidatorInterface, err error) {
	b.handleActionFuns("Validator")
	err = b.GetError()
	if err != nil {
		return
	}
	res = b.ValidatorInstance
	return
}

// 设置验证器实例
func (b *Builder) setValidator(validator validate.ValidatorInterface) (err error) {
	err = b.GetError()
	if err != nil {
		return
	}
	b.ValidatorInstance = validator
	return
}

// 获取验证器实例，链式操作未配置的验证器实例，则使用空验证器
func (b *Builder) GetValidator() (res validate.ValidatorInterface, err error) {
	value, err := b.GetValidatorInstance()
	if err != nil {
		return
	}
	if value == nil {
		res = &yunjValidator.Validator{}
		res.InitValidator(res)
		err = b.setValidator(res)
		return
	}
	res = value
	return
}

// 校验数据
func (b *Builder) CheckDatas(datas map[string]any, rules map[string]any, titles map[string]string, scene string) (err error) {
	if len(rules) == 0 {
		return
	}
	// 验证
	validator, err := b.GetValidator()
	if err != nil {
		return
	}
	datas["builder"] = b.builderInstance
	err = util.DatasValidate(validator, datas, rules, titles, scene)
	return
}

// 校验表单字段
func (b *Builder) CheckFormFields(datas map[string]any, fields []form.FieldInterface, scene string) (err error) {
	if len(fields) <= 0 {
		return
	}
	// 获取字段校验规则和标题
	rules := map[string]any{}
	titles := map[string]string{}
	var readonly bool
	var id, verify, title, verifyTitle string
	for _, field := range fields {
		readonly, err = field.GetFieldReadonly()
		if err != nil {
			return
		}
		if readonly {
			continue
		}
		id, err = field.GetFieldId()
		if err != nil {
			return
		}
		verify, err = field.GetFieldVerify()
		if err != nil {
			return
		}
		if verify == "" {
			continue
		}
		verifyTitle, err = field.GetFieldVerifyTitle()
		if err != nil {
			return
		}
		if verifyTitle == "" {
			title, err = field.GetFieldTitle()
			if err != nil {
				return
			}
			verifyTitle = title
			if verifyTitle == "" {
				verifyTitle = id
			}
		}
		rules[id] = verify
		titles[id] = verifyTitle
	}

	// 验证
	validator, err := b.GetValidator()
	if err != nil {
		return
	}
	datas["builder"] = b.builderInstance
	err = util.DatasValidate(validator, datas, rules, titles, scene)
	return
}

// 获取构建器操作执行顺序
func (b *Builder) getActionHandleSort() (actions []string) {
	return b.ActionHandleSort
}

// 获取构建器操作处理方法集合
func (b *Builder) getActionHandleFuns() (funs map[string][]any, err error) {
	err = b.GetError()
	if err != nil {
		return
	}
	funs = b.ActionHandleFuns
	return
}

// 设置构建器操作处理方法集合
func (b *Builder) setActionHandleFuns(funs map[string][]any) (err error) {
	err = b.GetError()
	if err != nil {
		return
	}
	b.ActionHandleFuns = funs
	return
}

// 增加构建器操作处理方法
func (b *Builder) addActionHandleFuns(action string, fun any) (err error) {
	err = b.GetError()
	if err != nil {
		return
	}
	actionHandleFuns, err := b.getActionHandleFuns()
	if err != nil {
		return
	}

	if actionHandleFuns == nil {
		actionHandleFuns = make(map[string][]any)
	}
	funcs, exists := actionHandleFuns[action]
	if !exists {
		actionHandleFuns[action] = []any{fun}
	} else {
		actionHandleFuns[action] = append(funcs, fun)
	}

	err = b.setActionHandleFuns(actionHandleFuns)
	return
}

// 获取构建器实例的错误前缀
func (b *Builder) getErrPrefix() (prefix string, err error) {
	err = b.GetError()
	if err != nil {
		return
	}
	prefix = b.ErrPrefix
	return
}

// 设置构建器实例的错误前缀
func (b *Builder) setErrPrefix(prefix string) (err error) {
	err = b.GetError()
	if err != nil {
		return
	}
	b.ErrPrefix = prefix
	return
}

// 执行操作处理方法
// actions: 指定执行的操作名称
func (b *Builder) handleActionFuns(actions ...string) {
	actionHandleSort := b.getActionHandleSort()
	actionHandleFuns, _ := b.getActionHandleFuns()
	if actionHandleFuns == nil || len(actionHandleSort) == 0 {
		return
	}
	for _, action := range actionHandleSort {
		funcs, exists := actionHandleFuns[action]
		if !exists || len(funcs) <= 0 || (len(actions) > 0 && !slices.Contains(actions, action)) {
			continue
		}
		var err error
		for _, fun := range funcs {
			if err = b.GetError(); err != nil {
				return
			}
			handleFunName := "Handle" + action + "Func"
			// 获取方法对应的反射值
			handleFunMethod := b.builderInstancePtr.MethodByName(handleFunName)
			// 检查方法是否存在且可调用
			if handleFunMethod.IsValid() {
				// 方法输入参数
				handleFunMethodArgs := []reflect.Value{reflect.ValueOf(fun)}
				// 调用方法
				handleFunMethod.Call(handleFunMethodArgs)
			}
		}
		// 防止重复执行
		delete(actionHandleFuns, action)
	}
	b.setActionHandleFuns(actionHandleFuns)
}

// 渲染输出
func (b *Builder) Assign() {
	ctx := b.GetGinContext()
	if util.IsAsync(ctx) {
		b.Async()
	} else {
		b.View()
	}
}

// 视图渲染输出
func (b *Builder) View() {
	builderType, _ := b.GetType()
	ctx := b.GetGinContext()
	args := b.builderInstance.viewArgs()

	// 构建器渲染参数
	builderTypeArgs := map[string]map[string]any{}
	if ctxBuilderTypeArgs, exists := response.GetCtxRenderHtmlData[map[string]map[string]any](ctx, builderType); exists {
		builderTypeArgs = ctxBuilderTypeArgs
	}
	builderId, _ := b.GetId()
	builderTypeArgs[builderId] = args
	response.SetCtxRenderHtmlData(ctx, builderType, builderTypeArgs)

	// 构建器脚本文件渲染参数
	builderScriptFileList, _ := b.GetScriptFileList()
	response.SetCtxRenderScriptFileList(ctx, builderScriptFileList)
}

// 构建器视图模板配置数据
func (b *Builder) viewArgs() (args map[string]any) {
	b.builderInstance.handleActionFuns()
	if err := b.GetError(); err != nil {
		ctx := b.GetGinContext()
		util.RedirectAdminTips(ctx, errcodeEnum.ERROR, err.Error())
	}
	args = map[string]any{}
	return
}

// 异步处理前执行
func (b *Builder) BeforeHandleAsync(params map[string]any) (err error) {
	return
}

// 异步输出
func (b *Builder) Async() {
	// 获取数据
	ctx := b.GetGinContext()
	params, _ := util.PostParams(ctx)
	if params == nil {
		return
	}
	// 判断是否当前验证器
	builderId, _ := b.GetId()
	paramBuilderId, builderIdExists := params["builder_id"]
	builderAsyncType, builderAsyncTypeExists := params["builder_async_type"]
	builderAsyncTypeStr, builderAsyncTypeIsStr := builderAsyncType.(string)
	if !builderIdExists || builderId != paramBuilderId || !builderAsyncTypeExists || !builderAsyncTypeIsStr {
		return
	}
	// 处理前执行
	// typ, _ := b.GetType()
	// errPrefix := fmt.Sprintf("构建器 %s[%s] ", typ, builderId)
	// 进行基础验证
	params["builder"] = b.builderInstance
	// validatorErrPrefix := fmt.Sprintf("%s异步基础验证失败！", errPrefix)
	validator, err := b.GetBuilderValidator()
	if err != nil {
		// fmt.Printf("构建器验证器获取：%s%v\r\n", validatorErrPrefix, err)
		return
	}
	err = validator.SetDatas(params)
	if err != nil {
		// fmt.Printf("构建器验证器验证参数设置：%s%v\r\n", validatorErrPrefix, err)
		return
	}
	err = validator.CheckScene("AsyncRequest")
	if err != nil {
		// fmt.Printf("构建器异步请求校验：%s%v\r\n", validatorErrPrefix, err)
		return
	}
	params, err = validator.GetDatas()
	if err != nil {
		// fmt.Printf("构建器异步请求数据获取：%s%v\r\n", validatorErrPrefix, err)
		return
	}

	// 异步处理前执行
	err = b.builderInstance.BeforeHandleAsync(params)
	if err != nil {
		// fmt.Printf("构建器异步处理前执行：%s%v", errPrefix, err)
		return
	}

	handleAsyncMethodName := "HandleAsync" + util.UcFirst(builderAsyncTypeStr)
	// 获取 builder 的反射值(指针)
	handleAsyncMethod := b.builderInstancePtr.MethodByName(handleAsyncMethodName)
	// 检查方法是否存在且可调用
	if handleAsyncMethod.IsValid() {
		// 方法输入参数
		handleAsyncMethodArgs := []reflect.Value{reflect.ValueOf(params)}
		// 调用方法，获取结果
		res := handleAsyncMethod.Call(handleAsyncMethodArgs)
		// 响应结果，并结束程序执行
		ctx := b.GetGinContext()
		if len(res) > 0 {
			result := res[0].Interface()
			resJsonData, ok := result.(*response.JsonData)
			if ok {
				resJsonData.AbortResponse(ctx)
			} else {
				response.AbortSuccess(ctx, result)
			}
		} else {
			response.AbortSuccess(ctx, nil)
		}
	}
}

// 获取构建器错误
func (b *Builder) GetError() error {
	return b.Err
}

// 设置构建器错误
func (b *Builder) setError(err any) error {
	if _err := b.GetError(); _err != nil {
		return _err
	}
	var resErrMsg string
	if _errMsg, ok := err.(string); ok {
		resErrMsg = _errMsg
	} else if _err, ok := err.(error); ok {
		resErrMsg = _err.Error()
	} else {
		resErrMsg = "未知错误！"
	}

	// 错误前缀
	errPrefix, _ := b.getErrPrefix()
	if errPrefix == "" {
		errPrefix = fmt.Sprintf("构建器%s[%s]", b.Type, b.Id)
		b.setErrPrefix(errPrefix)
	}

	if !strings.HasPrefix(resErrMsg, errPrefix) {
		resErrMsg = errPrefix + resErrMsg
	}
	newErr := errors.New(resErrMsg)
	b.Err = newErr
	return newErr
}
